package cn.com.bsoft.cloud.kotlin


import org.apache.commons.text.CharacterPredicate
import org.apache.commons.text.RandomStringGenerator
import java.io.PrintWriter
import java.io.StringWriter
import java.beans.Introspector
import java.io.ByteArrayOutputStream
import java.io.InputStream


/**
 * Created by zarra on 2017/7/7.
 */

@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
annotation class NoArg

@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
annotation class AllOpen


class StatusAndMessageError(val status: Int?, message: String?, prev: Throwable?) : RuntimeException(message, prev) {
    constructor(status: Int?, prev: Throwable) : this(status, null, prev)
    constructor(prev: Throwable) : this(null, null, prev)
    constructor(status: Int?, message: String?) : this(status, message, null)
    constructor(status: Int?) : this(status, null, null)
    constructor(message: String?) : this(-1, message, null)
}


fun randomString(length: Int, accept: String = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890~!@#$%&*()-=+{}[]/<>?"): String {
    val generator = RandomStringGenerator.Builder().filteredBy(
            CharacterPredicate { c ->
                if (c > Char.MAX_SURROGATE.toInt()) false
                else
                    accept.contains(c.toChar())
            }
    ).build()

    return generator.generate(length)
}


val Throwable.stackTraceMessage: String
    get() {
        val sw = StringWriter()
        val pw = PrintWriter(sw)
        printStackTrace(pw)
        return sw.toString()
    }

fun <T : Any> T.getProperty(propertyName: String): Any? {
    val beanInfo = Introspector.getBeanInfo(this.javaClass)
    val descriptors = beanInfo.propertyDescriptors
    return if (descriptors.none {
                it.name == propertyName
            }) {
        null
    } else descriptors.first {
        it.name == propertyName
    }?.readMethod?.invoke(this)
}

fun <T : Any> T.setProperty(propertyName: String, value: Any?) {
    val beanInfo = Introspector.getBeanInfo(this.javaClass)
    val descriptors = beanInfo.propertyDescriptors
    if (descriptors.none {
                it.name == propertyName
            }) {
        null
    } else descriptors.first {
        it.name == propertyName
    }?.writeMethod?.invoke(this, value)
}
